#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <pthread.h>
#include <assert.h>
#include <errno.h>
#include "jhash.h"

struct entry_s {
	struct entry_s *next;
	uint64_t key;
	uint64_t value;
};

//下面这个hash表结构，需要参赛者自己定义。
typedef struct {
	pthread_mutex_t lock;
	uint64_t max_elem;
	struct entry_s **bucket;
} MyHashMap;


//创建Hash表，最大元素数量是max_elem。
MyHashMap *myHashMapCreate(uint64_t max_elem) {
	MyHashMap *h;
	int ret;

	assert(max_elem > 0 && max_elem < 50000000UL);
	h = malloc(sizeof(*h));
	assert(h);
	h->bucket = malloc(max_elem * sizeof(struct entry_s *));
	assert(h->bucket);
	memset(h->bucket, 0, max_elem * sizeof(struct entry_s *));
	assert(h->bucket);
	h->max_elem = max_elem;
	ret = pthread_mutex_init(&h->lock, NULL);
	assert(ret == 0);

	return h;
}

//返回指向这个entry的room
static struct entry_s **lookup(MyHashMap *h, uint64_t key, uint64_t *bkt_idx)
{
	uint64_t hval;
	struct entry_s **pp, *p;

	hval = rte_jhash(&key, sizeof(key), 0);
	*bkt_idx = hval % h->max_elem;
	for (pp = &h->bucket[*bkt_idx]; *pp != NULL; pp = &((*pp)->next)) {
		p = *pp;
		if (key == p->key)
			return pp;
	}
	return NULL;
}

// 向hash表中添加元素，键值分别为key/value。
// 成功返回0。
// 如果该key在hash表中已经存在，返回-EEXIST；
// 如果hash表中元素数量超过了max_elem，则返回-ENOMEM；
int myHashMapPut(MyHashMap *obj, uint64_t key, uint64_t value)
{
	int ret, my_ret = 0;
	uint64_t idx;
	struct entry_s *e, **pp;

	ret = pthread_mutex_lock(&obj->lock);
	assert(ret == 0);

	pp = lookup(obj, key, &idx);
	if (pp != NULL) {
		my_ret = -EEXIST;
		goto done;
	}

	e = malloc(sizeof(*e));
	e->key = key;
	e->value = value;

	e->next = obj->bucket[idx];
	obj->bucket[idx] = e;

done:
	ret = pthread_mutex_unlock(&obj->lock);
	assert(ret == 0);

	return my_ret;
}

//在hash表中查找键为key的元素，并返回对应的值。 如果key不存在，则返回(uint64_t)-1。
uint64_t myHashMapGet(MyHashMap *obj, uint64_t key)
{
	int ret;
	uint64_t my_ret;
	uint64_t idx;
	struct entry_s **pp;

	ret = pthread_mutex_lock(&obj->lock);
	assert(ret == 0);

	pp = lookup(obj, key, &idx);

	my_ret = (pp == NULL ? (uint64_t)-1 : (*pp)->value);

	ret = pthread_mutex_unlock(&obj->lock);
	assert(ret == 0);

	return my_ret;
}

//从hash表中删除键为key的元素。
//如果成功返回0
//如果key不存在，则返回-ENOENT
int myHashMapRemove(MyHashMap *obj, uint64_t key)
{
	int ret;
	int my_ret = 0;
	uint64_t idx;
	struct entry_s *e, **pp;

	ret = pthread_mutex_lock(&obj->lock);
	assert(ret == 0);
	pp = lookup(obj, key, &idx);
	if (pp == NULL) {
		my_ret = -ENOENT;
		goto done;
	}

	e = *pp;
	*pp = e->next;
	free(e);
done:
	ret = pthread_mutex_unlock(&obj->lock);
	assert(ret == 0);
	return my_ret;
}

//销毁hash表，并释放该Hash表所有占用的内存。
void myHashMapFree(MyHashMap *obj) {
	pthread_mutex_destroy(&obj->lock);
	free(obj->bucket);
	free(obj);
}

